/****************************************************************************
* Copyright (c) 2008, j. montgomery, ATGi                                   *
* All rights reserved.                                                      *
*                                                                           *
* Redistribution and use in source and binary forms, with or without        *
* modification, are permitted provided that the following conditions        *
* are met:                                                                  *
*                                                                           *
* - Redistributions of source code must retain the above copyright          *
*   notice, this list of conditions and the following disclaimer.           *
*                                                                           *
* - Redistributions in binary form must reproduce the above                 *
*   copyright notice, this list of conditions and the following             *
*   disclaimer in the documentation and/or other materials provided         *
*   with the distribution.                                                  *
*                                                                           *
* - Neither the name of ATGi nor the names of its contributors may          *
*   be used to endorse or promote products derived from this software       *
*   without specific prior written permission.                              *
*                                                                           *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            *
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES                  *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR        *
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)        *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       *
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)             *
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED       *
* OF THE POSSIBILITY OF SUCH DAMAGE.                                        *
*****************************************************************************
*/
using System;
using System.Collections;
using System.Text;

namespace DnSmtp.Message
{
	/// <summary>
	/// Represents a Composite Message Type (a collection of discrete types)
	/// </summary>
	/// <remarks>
	/// http://www.faqs.org//rfcs/rfc2045.html
	/// 
	/// From RFC 2045
	/// content := "Content-Type" ":" type "/" subtype
	///				*(";" parameter)
	///				; Matching of media type and subtype
	///				; is ALWAYS case-insensitive.
	///  
	/// type := discrete-type / composite-type
	///  
	/// discrete-type := "text" / "image" / "audio" / "video" /
	///					 "application" / extension-token
	///  
	/// composite-type := "message" / "multipart" / extension-token
	/// 
	/// extension-token := ietf-token / x-token
	/// 
	/// ietf-token := (An extension token defined by a
	///					standards-track RFC and registered
	///					with IANA.)
	///
	/// x-token := (The two characters "X-" or "x-" followed, with
	///				no intervening white space, by any token)
	///				
	///	tspecials :=  "(" / ")" / "<" / ">" / "@" /
	///					"," / ";" / ":" / "\" / <">
	///					"/" / "[" / "]" / "?" / "="
	///					; Must be in quoted-string,
	///					; to use within parameter values
	/// </remarks>
	public class MessageContentCollection : CollectionBase, IMailContent, ICloneable
	{
		#region Fields
		private MimeType _mimetype;

		private string _preamble = MailMessage.CRLF 
			+ "If you are reading this text, you might want to" 
			+ MailMessage.CRLF 
			+ "consider changing your mail reader to one that" 
			+ MailMessage.CRLF 
			+ "understands how to properly display multipart messages." 
			+ MailMessage.CRLF;
		#endregion Fields

		#region Constructors
		public MessageContentCollection() 
		{
			// Default Mimetype is Multipart Alternative
			this.MimeType = MimeType.MultipartAlternative;
		}
		#endregion Constructors

		#region Properties
		public MimeType MimeType
		{
			get { return _mimetype; }
			set
			{
				if(value.ToString().StartsWith("multipart"))
				{
					_mimetype = value;
				}
				else 
				{
					throw new ApplicationException("MessageContentCollections MimeType can only be Multipart/*.");
				}
			}
		}

		public IMailContent this[ int index ]  
		{
			get  
			{
				return( (IMailContent) List[index] );
			}
			set  
			{
				List[index] = value;
			}
		}

		public string MultipartPreamble 
		{
			get 
			{
				return _preamble;
			}
			set 
			{
				_preamble = value;
			}
		}

		public string Preamble 
		{
			get {return _preamble; }
			set	{ _preamble = value; }
		}
		#endregion Properties

		#region Collection Implementation
		public int Add( IMailContent value )  
		{
			return( List.Add( value ) );
		}

		public int IndexOf( IMailContent value )  
		{
			return( List.IndexOf( value ) );
		}

		public void Insert( int index, IMailContent value )  
		{
			List.Insert( index, value );
		}

		public void Remove( IMailContent value )  
		{
			List.Remove( value );
		}

		public bool Contains( IMailContent value )  
		{
			// If value is not of type MailContent, this will return false.
			return( List.Contains( value ) );
		}

		protected override void OnInsert( int index, Object value )  
		{
			// Insert additional code to be run only when inserting values.
		}

		protected override void OnRemove( int index, Object value )  
		{
			// Insert additional code to be run only when removing values.
		}

		protected override void OnSet( int index, Object oldValue, Object newValue )  
		{
			// Insert additional code to be run only when setting values.
		}

		protected override void OnValidate( Object value )  
		{
			if(!(value is IMailContent))
			{
				throw new ArgumentException( "value must be of type IMailContent.", "value" );
			}
		}
		#endregion Collection Implementation

		#region ICloneable Members

		public object Clone()
		{
			MessageContentCollection mcc = new MessageContentCollection();
			mcc._mimetype = this._mimetype;
			mcc._preamble = this._preamble;
			foreach(IMailContent content in this.List) 
			{
				mcc.Add(content);
			}
			return mcc;
		}

		#endregion

		public virtual string BuildMessage() 
		{
			if (this.Count > 1)
			{
				// There's more than one item, this is a multipart message
				return this.BuildMultipartContent();
			}
			else if (this.Count == 1 && (this.MimeType.Equals(MimeType.MultipartMixed) || this.MimeType.Equals(MimeType.MultipartAlternative)))
			{
				// There's one multipart item
				return this.BuildMultipartContent();
			}
			else if (this.Count == 1 && !this.MimeType.Equals(MimeType.MultipartMixed) && !this.MimeType.Equals(MimeType.MultipartAlternative))
			{
				// There's one item and it's not multipart/mixed or multipart/alternative
				// so there's no need to do anything but build the one message
				return this[0].BuildMessage();
			}
			else
			{
				// There are no items
				// Do nothing, there's no message
				return string.Empty;
			}
		}

		private string BuildMultipartContent() 
		{
			string mailBoundry = "--Next_" + MailMessage.GenerateMailBoundary();
			StringBuilder sb = new StringBuilder();

			// Setup Boundry and Content Type for Multipart
			sb.Append(MailMessage.CONTENT_TYPE_HEADER);
            sb.Append(_mimetype.ToString());
            sb.Append(";");
            sb.Append(MailMessage.CRLF);
			sb.Append("              ");
            sb.Append(MailMessage.BOUNDRY_HEADER);
            sb.Append("\"");
            sb.Append(mailBoundry);
            sb.Append("\"");
            sb.Append(MailMessage.CRLF);
			// Print Preamble
			sb.Append(_preamble);
            sb.Append(MailMessage.CRLF);
			// Pring 1st boundry
			sb.Append("--");
            sb.Append(mailBoundry);
				
			foreach(IMailContent message in this) 
			{
				sb.Append(MailMessage.CRLF);
				sb.Append(message.BuildMessage());
				sb.Append(MailMessage.CRLF);

				// Next Boundry
				sb.Append("--");
                sb.Append(mailBoundry);
			}
			// End Boundry
			sb.Append("--");
            sb.Append(MailMessage.CRLF);

			return sb.ToString();
		}
	}

}
